#include "Renderer_PCH.h"
#include "MaterialRequest.h"

/*--------------------------------------------------------------------------*/

MaterialRequest::MaterialRequest(const std::string& path) :
	m_path(path)
{

}

/*--------------------------------------------------------------------------*/

MaterialRequest::~MaterialRequest()
{

}

/*--------------------------------------------------------------------------*/

void* MaterialRequest::DoRequest()
{
	pugi::xml_document mfile;
	bool loadingResult = mfile.load_file(m_path.c_str());
	__Check(loadingResult);

	if (!loadingResult)
	{
		__Crash("Failed to open or parse file: %s", m_path.c_str());
		return false;
	}

	/*--------------------------------------------------------------------------*/

	//RMaterial* material = g_Renderer->GetRendererStorageMgr()->CreateMaterial(::GetFileName(m_path));
	const std::string matname		= ::GetFileName(m_path);
	pugi::xml_node node_material	= mfile.child("material");
	pugi::xml_node node_defs		= node_material.child("defs");
	pugi::xml_node node_passes		= node_material.child("passes");

	/*--------------------------------------------------------------------------*/

	for (pugi::xml_node blendstate = node_defs.child("blendstate"); blendstate; blendstate = blendstate.next_sibling("blendstate"))
	{
		RBlendState* state = g_Renderer->GetRendererStorageMgr()->CreateBlendState(blendstate.attribute("name").as_string("default"));

		if (state)
		{
			pugi::xml_node srcfactor		= blendstate.child("srcfactor");

			if (srcfactor)
			{
				state->SetSrcFactor(ToEnum(srcfactor.attribute("value").as_string()));
			}

			pugi::xml_node dstfactor		= blendstate.child("dstfactor");

			if (dstfactor)
			{
				state->SetDstFactor(ToEnum(dstfactor.attribute("value").as_string()));
			}

			pugi::xml_node blendequation	= blendstate.child("blendequation");

			if (blendequation)
			{
				state->SetBlendEquation(ToEnum(blendequation.attribute("value").as_string()));
			}
		}
	}

	/*--------------------------------------------------------------------------*/

	for (pugi::xml_node rasterizerstate = node_defs.child("rasterizerstate"); rasterizerstate; rasterizerstate = rasterizerstate.next_sibling("rasterizerstate"))
	{
		RRasterizerState* state = g_Renderer->GetRendererStorageMgr()->CreateRasterizerState(rasterizerstate.attribute("name").as_string("default"));

		if (state)
		{
			pugi::xml_node frontface		= rasterizerstate.child("frontface");

			if (frontface)
			{
				state->SetFrontFace(ToEnum(frontface.attribute("value").as_string()));
			}

			pugi::xml_node cullface			= rasterizerstate.child("cullface");

			if (cullface)
			{
				state->SetCullFace(ToEnum(cullface.attribute("value").as_string()));
			}

			pugi::xml_node frontpolygonmode = rasterizerstate.child("frontpolygonmode");

			if (frontpolygonmode)
			{
				state->SetFrontPolygonMode(ToEnum(frontpolygonmode.attribute("value").as_string()));
			}

			pugi::xml_node backpolygonmode	= rasterizerstate.child("backpolygonmode");

			if (backpolygonmode)
			{
				state->SetBackPolygonMode(ToEnum(backpolygonmode.attribute("value").as_string()));
			}

			pugi::xml_node colormask		= rasterizerstate.child("colormask");

			if (colormask)
			{
				state->SetColorMask(ToEnum(colormask.attribute("value").as_string()));
			}
		}
	}

	/*--------------------------------------------------------------------------*/

	for (pugi::xml_node depthstencilstate = node_defs.child("depthstencilstate"); depthstencilstate; depthstencilstate = depthstencilstate.next_sibling("depthstencilstate"))
	{
		RDepthstencilState* state = g_Renderer->GetRendererStorageMgr()->CreateDepthstencilState(depthstencilstate.attribute("name").as_string("default"));

		if (state)
		{
			pugi::xml_node depthtest		= depthstencilstate.child("depthtest");

			if (depthtest)
			{
				state->SetDepthTest(ToEnum(depthtest.attribute("value").as_string()));
			}

			pugi::xml_node depthmask		= depthstencilstate.child("depthmask");

			if (depthmask)
			{
				state->SetDepthMask(ToEnum(depthmask.attribute("value").as_string()));
			}

			pugi::xml_node depthfunc		= depthstencilstate.child("depthfunc");

			if (depthfunc)
			{
				state->SetDepthFunc(ToEnum(depthfunc.attribute("value").as_string()));
			}

			pugi::xml_node stenciltest		= depthstencilstate.child("stenciltest");

			if (stenciltest)
			{
				state->SetStencilTest(ToEnum(stenciltest.attribute("value").as_string()));
			}

			pugi::xml_node stencilmask		= depthstencilstate.child("stencilmask");

			if (stencilmask)
			{
				state->SetStencilMask(ToEnum(stencilmask.attribute("value").as_string()));
			}
		}
	}

	/*--------------------------------------------------------------------------*/

	for (pugi::xml_node samplerstate = node_defs.child("samplerstate"); samplerstate; samplerstate = samplerstate.next_sibling("samplerstate"))
	{
		RSamplerState* state = g_Renderer->GetRendererStorageMgr()->CreateSamplerState(samplerstate.attribute("name").as_string("default"));

		if (state)
		{
			pugi::xml_node wrap_s			= samplerstate.child("wrap_s");

			if (wrap_s)
			{
				state->SetWrapS(ToEnum(wrap_s.attribute("value").as_string()));
			}

			pugi::xml_node wrap_r			= samplerstate.child("wrap_r");

			if (wrap_r)
			{
				state->SetWrapR(ToEnum(wrap_r.attribute("value").as_string()));
			}

			pugi::xml_node wrap_t			= samplerstate.child("wrap_t");

			if (wrap_t)
			{
				state->SetWrapT(ToEnum(wrap_t.attribute("value").as_string()));
			}

			pugi::xml_node minfilter		= samplerstate.child("minfilter");

			if (minfilter)
			{
				state->SetMinFilter(ToEnum(minfilter.attribute("value").as_string()));
			}

			pugi::xml_node magfilter		= samplerstate.child("magfilter");

			if (magfilter)
			{
				state->SetMagFilter(ToEnum(magfilter.attribute("value").as_string()));
			}

			glGenSamplers(1, &state->m_handle);
			glSamplerParameteri(state->m_handle, GL_TEXTURE_WRAP_S, state->GetWrapS());
			glSamplerParameteri(state->m_handle, GL_TEXTURE_WRAP_R, state->GetWrapR());
			glSamplerParameteri(state->m_handle, GL_TEXTURE_WRAP_T, state->GetWrapT());
			glSamplerParameteri(state->m_handle, GL_TEXTURE_MIN_FILTER, state->GetMinFilter());
			glSamplerParameteri(state->m_handle, GL_TEXTURE_MAG_FILTER, state->GetMagFilter());
		}
	}

	/*--------------------------------------------------------------------------*/

// 	for (pugi::xml_node shader = node_defs.child("shader"); shader; shader = shader.next_sibling("shader"))
// 	{
// 		std::string shadername = shader.attribute("name").as_string("default");
// 		EShader::Type shadertype = EShader::Unknown;
// 
// 		switch (shader.attribute("type").as_string("v")[0])
// 		{
// 		case 'v':
// 			shadertype = EShader::VertexShader;
// 			break;
// 
// 		case 'g':
// 			shadertype = EShader::GeometryShader;
// 			break;
// 
// 		case 'f':
// 			shadertype = EShader::FragmentShader;
// 			break;
// 		}
// 
// 		pugi::xml_node techs = shader.child("techs");
// 		std::string glsl = std::string(shader.child("glsl").child_value()) + std::string("\n");
// 
// 		for (pugi::xml_node tech = techs.child("tech"); tech; tech = tech.next_sibling("tech"))
// 		{
// 			std::string techname = tech.attribute("name").as_string("DEFAULT");
// 			std::string shadertechname = shadername + "@" + techname;
// 
// 			RShader* shader = g_Renderer->GetRendererStorageMgr()->CreateShader(shadertechname, shadertype);
// 
// 			if (shader)
// 			{
// 				shader->SetSourceCode(glsl);
// 
// 				shader->AddMacro("TECH_" + techname, "1");
// 				
// 				if (shadertype == EShader::FragmentShader || shadertype == EShader::VertexShader)
// 				{
// 					pugi::xml_node semantics = tech.child("semantics");
// 					for (pugi::xml_node semantic = semantics.child("semantic"); semantic; semantic = semantic.next_sibling("semantic"))
// 					{
// 						shader->AddSemantic(semantic.attribute("name").as_string("name_not_set"), semantic.attribute("type").as_string("Unknown"));
// 					}
// 				}		
// 
// 				pugi::xml_node uniforms = tech.child("uniforms");
// 				for (pugi::xml_node uniform = uniforms.child("uniform"); uniform; uniform = uniform.next_sibling("uniform"))
// 				{
// 					shader->AddConstant(uniform.attribute("name").as_string("name_not_set"));
// 				}
// 
// 				pugi::xml_node samplers = tech.child("samplers");
// 				for (pugi::xml_node sampler = samplers.child("sampler"); sampler; sampler = sampler.next_sibling("sampler"))
// 				{
// 					shader->AddSampler(	sampler.attribute("name").as_string("name_not_set"), 
// 										sampler.attribute("texture").as_string("default"), 
// 										sampler.attribute("sampler").as_string("default"));
// 				}
// 
// 				shader->WriteHeader();
// 				shader->CompileShader();
// 			}
// 		}
// 	}

	/*--------------------------------------------------------------------------*/

	for (pugi::xml_node pass = node_passes.child("pass"); pass; pass = pass.next_sibling("pass"))
	{
		std::string passname = pass.attribute("name").as_string("noname");
		RMaterial* material = g_Renderer->GetRendererStorageMgr()->CreateMaterial(matname + "_" + passname);

		if (material)
		{
			std::string blendstate			= pass.child("blendstate").attribute("name").as_string("default");
			std::string rasterizerstate		= pass.child("rasterizerstate").attribute("name").as_string("default");
			std::string depthstencilstate	= pass.child("depthstencilstate").attribute("name").as_string("default");
			
			std::string vShaderCode			= std::string(pass.child("vertexshader").child_value());
			std::string gShaderCode			= std::string(pass.child("geometryshader").child_value());
			std::string fShaderCode			= std::string(pass.child("fragmentshader").child_value());

			material->m_blendstate			= g_Renderer->GetRendererStorageMgr()->GetBlendState(blendstate);
			material->m_rasterizerstate		= g_Renderer->GetRendererStorageMgr()->GetRasterizerState(rasterizerstate);
			material->m_depthstencilstate	= g_Renderer->GetRendererStorageMgr()->GetDepthstencilState(depthstencilstate);

			pugi::xml_node macros			= pass.child("macros");
			for (pugi::xml_node macro = macros.child("macro"); macro; macro = macro.next_sibling("macro"))
			{
				material->m_macros.push_back(RMacro(macro.attribute("name").as_string("NONAME"), macro.attribute("value").as_string("1")));
			}

			pugi::xml_node samplers = pass.child("samplers");
			for (pugi::xml_node sampler = samplers.child("sampler"); sampler; sampler = sampler.next_sibling("sampler"))
			{
				RSamplerState* samplerstatePtn = g_Renderer->GetRendererStorageMgr()->GetSamplerState(sampler.attribute("sampler").as_string("default"));
				__Check(samplerstatePtn);

				RTexture* texturePtn = g_Renderer->GetRendererStorageMgr()->GetTexture(sampler.attribute("texture").as_string("default"));
				__Check(texturePtn);

				std::string name = sampler.attribute("name").as_string("default");

				material->m_samplers.push_back(RSampler(name, samplerstatePtn, texturePtn, -1));
			}

			material->CreateProgram(vShaderCode, gShaderCode, fShaderCode);

// 			RShader* vertexshaderPtn		= NULL;
// 			RShader* geometryshaderPtn		= NULL;
// 			RShader* fragmentshaderPtn		= NULL;
// 
// 			if (vShaderCode.length() >= 1)
// 			{
// 				vertexshaderPtn				= g_Renderer->GetRendererStorageMgr()->CreateShader("vs_" + matname + "_" + matname, EShader::VertexShader);
// 				vertexshaderPtn->SetSourceCode(vShaderCode);
// 			}
// 			
// 			if (gShaderCode.length() >= 1)
// 			{
// 				geometryshaderPtn			= g_Renderer->GetRendererStorageMgr()->CreateShader("gs_" + matname + "_" + matname, EShader::GeometryShader);
// 				geometryshaderPtn->SetSourceCode(gShaderCode);
// 			}
// 
// 			if (fShaderCode.length() >= 1)
// 			{
// 				fragmentshaderPtn			= g_Renderer->GetRendererStorageMgr()->CreateShader("fs_" + matname + "_" + matname, EShader::VertexShader);
// 				fragmentshaderPtn->SetSourceCode(fShaderCode);
// 			}
			
			bool success = false;//

			for(uint i = 0; i < 3; ++i)
			{
				RShader* shader = NULL;

// 				switch (i)
// 				{
// 				case 0:
// 				{
// 					shader = vertexshaderPtn;
// 					break;
// 				}
// 				case 1:
// 				{
// 					shader = geometryshaderPtn;
// 					break;
// 				}
// 				case 2:
// 				{
// 					shader = fragmentshaderPtn;
// 					break;
// 				}
// 				}

// 				if (shader)
// 				{
// 					for (auto sampler = shader->m_samplers.begin(); sampler != shader->m_samplers.end(); ++sampler)
// 					{
// 						RSamplerState* samplerstatePtn = g_Renderer->GetRendererStorageMgr()->GetSamplerState(sampler->GetSampler());
// 						__Check(samplerstatePtn);
// 
// 						RTexture* texturePtn = g_Renderer->GetRendererStorageMgr()->GetTexture(sampler->GetTexture());
// 						__Check(texturePtn);
// 
// 						material->m_samplers.push_back(RMaterialSampler(sampler->GetName(), samplerstatePtn, texturePtn));
// 					}
// 				}
			}


		}
	}

	__Info("[RENDERER] Material %s created", ::GetFileName(m_path).c_str());
	return (void*) 0xff;
}

/*--------------------------------------------------------------------------*/
